home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / emacs-complete / fsf / emacs / src / msdos.c < prev    next >
C/C++ Source or Header  |  1994-07-13  |  29KB  |  1,242 lines

  1. /* MS-DOS specific C utilities.
  2.    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* Contributed by Morten Welinder */
  21.  
  22. /* Note: some of the stuff here was taken from end of sysdep.c in demacs. */
  23.  
  24. #include <config.h>
  25.  
  26. #ifdef MSDOS
  27. #include "lisp.h"
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <sys/param.h>
  31. #include <sys/time.h>
  32. #include <dos.h>
  33. #include "dosfns.h"
  34. #include "msdos.h"
  35. #include "systime.h"
  36. #include "termhooks.h"
  37. #include "frame.h"
  38. #include <go32.h>
  39. #include <pc.h>
  40. #include <ctype.h>
  41. /* #include <process.h> */
  42. /* Damn that local process.h!  Instead we can define P_WAIT ourselves.  */
  43. #define P_WAIT 1
  44.  
  45. static int break_stat;     /* BREAK check mode status.    */
  46. static int stdin_stat;     /* stdin IOCTL status.        */
  47. static int extended_kbd; /* 101 (102) keyboard present.    */
  48.  
  49. int have_mouse;          /* Mouse present?        */
  50. static int mouse_last_x;
  51. static int mouse_last_y;
  52.  
  53. /*  Turn off Dos' Ctrl-C checking and inhibit interpretation of control chars
  54.     by Dos.  Determine the keyboard type.  */
  55. int
  56. dos_ttraw ()
  57. {
  58.   union REGS inregs, outregs;
  59.  
  60.   inregs.h.ah = 0xc0;
  61.   int86 (0x15, &inregs, &outregs);
  62.   extended_kbd = (!outregs.x.cflag) && (outregs.h.ah == 0);
  63.  
  64.   break_stat = getcbrk ();
  65.   setcbrk (0);
  66.   install_ctrl_break_check ();
  67.   have_mouse = mouse_init1 ();
  68.  
  69.   inregs.x.ax = 0x4400;    /* Get IOCTL status. */
  70.   inregs.x.bx = 0x00;    /* 0 = stdin. */
  71.   intdos (&inregs, &outregs);
  72.   stdin_stat = outregs.h.dl;
  73.  
  74.   inregs.x.dx = (outregs.x.dx | 0x0020) & 0x0027; /* raw mode */
  75.   inregs.h.al = 0x01;
  76.   intdos (&inregs, &outregs);
  77.   return !outregs.x.cflag;
  78. }
  79.  
  80. /*  Restore status of standard input and Ctrl-C checking.  */
  81. int
  82. dos_ttcooked ()
  83. {
  84.   union REGS inregs, outregs;
  85.  
  86.   setcbrk (break_stat);
  87.   if (have_mouse) mouse_off ();
  88.  
  89.   inregs.x.ax = 0x4401;    /* Set IOCTL status.    */
  90.   inregs.x.bx = 0x00;    /* 0 = stdin.        */
  91.   inregs.x.dx = stdin_stat;
  92.   intdos (&inregs, &outregs);
  93.   return !outregs.x.cflag;
  94. }
  95.  
  96. static unsigned short
  97. ibmpc_translate_map[] =
  98. {
  99.   /* --------------- 00 to 0f --------------- */
  100.   0, /* Ctrl Break */
  101.   0xff1b, /* Escape */
  102.   0xffb1, /* Keypad 1 */
  103.   0xffb2, /* Keypad 2 */
  104.   0xffb3, /* Keypad 3 */
  105.   0xffb4, /* Keypad 4 */
  106.   0xffb5, /* Keypad 5 */
  107.   0xffb6, /* Keypad 6 */
  108.   0xffb7, /* Keypad 7 */
  109.   0xffb8, /* Keypad 8 */
  110.   0xffb9, /* Keypad 9 */
  111.   0xffb0, /* Keypad 0 */
  112.   '-', '=',
  113.   0xff08, /* Backspace */
  114.   0xff74, /* (Shift) Tab [Tab doesn't use this table] */
  115.  
  116.   /* --------------- 10 to 1f --------------- */
  117.   'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']',
  118.   0xff8d, /* Keypad Enter */
  119.   0, /* Ctrl */
  120.   'a', 's',
  121.  
  122.   /* --------------- 20 to 2f --------------- */
  123.   'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',
  124.   0, /* Left shift */
  125.   '\\', 'z', 'x', 'c', 'v',
  126.  
  127.   /* --------------- 30 to 3f --------------- */
  128.   'b', 'n', 'm', ',', '.',
  129.   0xffaf, /* Grey / */
  130.   0, /* Right shift */
  131.   0xffaa, /* Grey * */
  132.   0, /* Alt */
  133.   ' ',
  134.   0, /* Caps Lock */
  135.   0xffbe, /* F1 */
  136.   0xffbf, /* F2 */
  137.   0xffc0, /* F3 */
  138.   0xffc1, /* F4 */
  139.   0xffc2, /* F5 */
  140.  
  141.   /* --------------- 40 to 4f --------------- */
  142.   0xffc3, /* F6 */
  143.   0xffc4, /* F7 */
  144.   0xffc5, /* F8 */
  145.   0xffc6, /* F9 */
  146.   0xffc7, /* F10 */
  147.   0, /* Num Lock */
  148.   0, /* Scroll Lock */
  149.   0xff50, /* Home */
  150.   0xff52, /* Up */
  151.   0xff55, /* Page Up */
  152.   0xffad, /* Grey - */
  153.   0xff51, /* Left */
  154.   0xffb5, /* Keypad 5 */
  155.   0xff53, /* Right */
  156.   0xffab, /* Grey + */
  157.   0xff57, /* End */
  158.  
  159.   /* --------------- 50 to 5f --------------- */
  160.   0xff54, /* Down */
  161.   0xff56, /* Page Down */
  162.   0xff63, /* Insert */
  163.   0xffff, /* Delete */
  164.   0xffbe, /* (Shift) F1 */
  165.   0xffbf, /* (Shift) F2 */
  166.   0xffc0, /* (Shift) F3 */
  167.   0xffc1, /* (Shift) F4 */
  168.   0xffc2, /* (Shift) F5 */
  169.   0xffc3, /* (Shift) F6 */
  170.   0xffc4, /* (Shift) F7 */
  171.   0xffc5, /* (Shift) F8 */
  172.   0xffc6, /* (Shift) F9 */
  173.   0xffc7, /* (Shift) F10 */
  174.   0xffbe, /* (Ctrl) F1 */
  175.   0xffbf, /* (Ctrl) F2 */
  176.  
  177.   /* --------------- 60 to 6f --------------- */
  178.   0xffc0, /* (Ctrl) F3 */
  179.   0xffc1, /* (Ctrl) F4 */
  180.   0xffc2, /* (Ctrl) F5 */
  181.   0xffc3, /* (Ctrl) F6 */
  182.   0xffc4, /* (Ctrl) F7 */
  183.   0xffc5, /* (Ctrl) F8 */
  184.   0xffc6, /* (Ctrl) F9 */
  185.   0xffc7, /* (Ctrl) F10 */
  186.   0xffbe, /* (Alt) F1 */
  187.   0xffbf, /* (Alt) F2 */
  188.   0xffc0, /* (Alt) F3 */
  189.   0xffc1, /* (Alt) F4 */
  190.   0xffc2, /* (Alt) F5 */
  191.   0xffc3, /* (Alt) F6 */
  192.   0xffc4, /* (Alt) F7 */
  193.   0xffc5, /* (Alt) F8 */
  194.  
  195.   /* --------------- 70 to 7f --------------- */
  196.   0xffc6, /* (Alt) F9 */
  197.   0xffc7, /* (Alt) F10 */
  198.   0xff6d, /* (Ctrl) Sys Rq */
  199.   0xff51, /* (Ctrl) Left */
  200.   0xff53, /* (Ctrl) Right */
  201.   0xff57, /* (Ctrl) End */
  202.   0xff56, /* (Ctrl) Page Down */
  203.   0xff50, /* (Ctrl) Home */
  204.   '1', '2', '3', '4', '5', '6', '7', '8', /* (Alt) */
  205.  
  206.   /* --------------- 80 to 8f --------------- */
  207.   '9', '0', '-', '=', /* (Alt) */
  208.   0xff55, /* (Ctrl) Page Up */
  209.   0xffc8, /* F11 */
  210.   0xffc9, /* F12 */
  211.   0xffc8, /* (Shift) F11 */
  212.   0xffc9, /* (Shift) F12 */
  213.   0xffc8, /* (Ctrl) F11 */
  214.   0xffc9, /* (Ctrl) F12 */
  215.   0xffc8, /* (Alt) F11 */
  216.   0xffc9, /* (Alt) F12 */
  217.   0xff52, /* (Ctrl) Up */
  218.   0xffae, /* (Ctrl) Grey - */
  219.   0xffb5, /* (Ctrl) Keypad 5 */
  220.  
  221.   /* --------------- 90 to 9f --------------- */
  222.   0xffab, /* (Ctrl) Grey + */
  223.   0xff54, /* (Ctrl) Down */
  224.   0xff63, /* (Ctrl) Insert */
  225.   0xffff, /* (Ctrl) Delete */
  226.   0xff09, /* (Ctrl) Tab */
  227.   0xffaf, /* (Ctrl) Grey / */
  228.   0xffaa, /* (Ctrl) Grey * */
  229.   0xff50, /* (Alt) Home */
  230.   0xff52, /* (Alt) Up */
  231.   0xff55, /* (Alt) Page Up */
  232.   0, /* NO KEY */
  233.   0xff51, /* (Alt) Left */
  234.   0, /* NO KEY */
  235.   0xff53, /* (Alt) Right */
  236.   0, /* NO KEY */
  237.   0xff57, /* (Alt) End */
  238.  
  239.   /* --------------- a0 to af --------------- */
  240.   0xff54, /* (Alt) Down */
  241.   0xff56, /* (Alt) Page Down */
  242.   0xff63, /* (Alt) Insert */
  243.   0xffff, /* (Alt) Delete */
  244.   0xffaf, /* (Alt) Grey / */
  245.   0xff09, /* (Alt) Tab */
  246.   0xff0d  /* (Alt) Enter */
  247. };
  248.  
  249. /* Get a char from keyboard.  Function keys are put into the event queue.  */
  250. static int
  251. dos_rawgetc ()
  252. {
  253.   struct input_event event;
  254.   struct timeval tv;
  255.   union REGS regs;
  256.   int ctrl_p, alt_p, shift_p;
  257.  
  258.   /* Calculate modifier bits */
  259.   regs.h.ah = extended_kbd ? 0x12 : 0x02;
  260.   int86 (0x16, ®s, ®s);
  261.   ctrl_p = ((regs.h.al & 4) != 0);
  262.   shift_p = ((regs.h.al & 3) != 0);
  263.   /* Please be very careful here not to break international keyboard support.
  264.      When Keyb.Com is loaded, the key marked `Alt Gr' is used for accessing
  265.      characters like { and } if their positions are overlaid.  */
  266.   alt_p = ((extended_kbd ? (regs.h.ah & 2) : (regs.h.al & 8)) != 0);
  267.  
  268.   /* The following condition is equivalent to `kbhit ()', except that
  269.      it uses the bios to do its job.  This pleases DESQview/X.  */
  270.   while ((regs.h.ah = extended_kbd ? 0x11 : 0x01),
  271.      int86 (0x16, ®s, ®s),
  272.      (regs.x.flags & 0x40) == 0)
  273.     {
  274.       union REGS regs;
  275.       register unsigned char c;
  276.       int sc, code;
  277.  
  278.       regs.h.ah = extended_kbd ? 0x10 : 0x00;
  279.       int86 (0x16, ®s, ®s);
  280.       c = regs.h.al;
  281.       sc = regs.h.ah;
  282.  
  283.       /* Determine from the scan code if a keypad key was pressed.  */
  284.       if (c >= '0' && c <= '9' && sc > 0xb)
  285.     sc = (c == '0') ? 0xb : (c - '0' + 1), c = 0;
  286.       else if (sc == 0x53 && c != 0xe0)
  287.     {
  288.       code = 0xffae; /* Keypad decimal point/comma.  */
  289.       goto nonascii;
  290.     }
  291.       else if (sc == 0xe0)
  292.     {
  293.       switch (c)
  294.         {
  295.         case 10: /* Ctrl Enter */
  296.         case 13:
  297.           sc = 0x1c;
  298.           break;
  299.         case '/':
  300.           sc = 0x35;
  301.           break;
  302.         default:
  303.           sc = 0;
  304.         };
  305.       c = 0;
  306.     }
  307.  
  308.       if (c == 0
  309.       || c == ' '
  310.       || alt_p
  311.       || (ctrl_p && shift_p)
  312.       || (c == 0xe0 && sc != 0)     /* Pseudo-key */
  313.       || sc == 0x37                 /* Grey * */
  314.       || sc == 0x4a                 /* Grey - */
  315.       || sc == 0x4e                 /* Grey + */
  316.       || sc == 0x0e)                /* Back space *key*, not Ctrl-h */
  317.       {
  318.     if (sc >= (sizeof (ibmpc_translate_map) / sizeof (short)))
  319.       code = 0;
  320.     else
  321.       code = ibmpc_translate_map[sc];
  322.     if (code != 0)
  323.       {
  324.         if (code >= 0x100)
  325.           {
  326.           nonascii:
  327.         event.kind = non_ascii_keystroke;
  328.         event.code = (code & 0xff) + 0xff00;
  329.           }
  330.         else
  331.           {
  332.         /* Don't return S- if we don't have to.  `shifted' is
  333.            supposed to be the shifted versions of the characters
  334.            in `unshifted'.  Unfortunately, this is only true for
  335.            US keyboard layout.  If anyone knows how to do this
  336.            right, please tell us.  */
  337.         static char *unshifted
  338.           = "abcdefghijklmnopqrstuvwxyz,./=;[\\]'-`0123456789";
  339.         static char *shifted
  340.           = "ABCDEFGHIJKLMNOPQRSTUVWXYZ<>?+:{|}\"_~)!@#$%^&*(";
  341.         char *pos;
  342.  
  343.         if (shift_p && (pos = strchr (unshifted, code)))
  344.           {
  345.             c = shifted[pos - unshifted];
  346.             shift_p = 0;
  347.           }
  348.         else
  349.           if (c == 0) c = code;
  350.         event.kind = ascii_keystroke;
  351.         event.code = c;
  352.           }
  353.         event.modifiers
  354.           = (shift_p ? shift_modifier : 0)
  355.         + (ctrl_p ? ctrl_modifier : 0)
  356.           + (alt_p ? meta_modifier : 0);
  357.         /* EMACS == Enter Meta Alt Control Shift */
  358.         event.frame_or_window = selected_frame;
  359.         gettimeofday (&tv, NULL);
  360.         event.timestamp = tv.tv_usec;
  361.         kbd_buffer_store_event (&event);
  362.       }
  363.       } else
  364.     return c;
  365.     }
  366.  
  367.   if (have_mouse)
  368.     {
  369.       int but, press, x, y, ok;
  370.  
  371.       /* Check for mouse movement *before* buttons.  */
  372.       mouse_check_moved ();
  373.  
  374.       for (but = 0; but < NUM_MOUSE_BUTTONS; but++)
  375.     for (press = 0; press < 2; press++)
  376.       {
  377.         if (press)
  378.           ok = mouse_pressed (but, &x, &y);
  379.         else
  380.           ok = mouse_released (but, &x, &y);
  381.         if (ok)
  382.           {
  383.         event.kind = mouse_click;
  384.         event.code = but;
  385.         event.modifiers
  386.           = (shift_p ? shift_modifier : 0)
  387.             + (ctrl_p ? ctrl_modifier : 0)
  388.               + (alt_p ? meta_modifier : 0)
  389.             + (press ? down_modifier : up_modifier);
  390.         event.x = x;
  391.         event.y = y;
  392.         event.frame_or_window = selected_frame;
  393.         gettimeofday (&tv, NULL);
  394.         event.timestamp = tv.tv_usec;
  395.         kbd_buffer_store_event (&event);
  396.           }
  397.       }
  398.     }
  399.  
  400.   return -1;
  401. }
  402.  
  403. static int prev_get_char = -1;
  404.  
  405. /* Return 1 if a key is ready to be read without suspending execution.  */
  406. dos_keysns ()
  407. {
  408.   if (prev_get_char != -1)
  409.     return 1;
  410.   else
  411.     return ((prev_get_char = dos_rawgetc ()) != -1);
  412. }
  413.  
  414. /* Read a key.  Return -1 if no key is ready.  */
  415. dos_keyread ()
  416. {
  417.   if (prev_get_char != -1)
  418.     {
  419.       int c = prev_get_char;
  420.       prev_get_char = -1;
  421.       return c;
  422.     }
  423.   else
  424.     return dos_rawgetc ();
  425. }
  426.  
  427. /* Hostnames for a pc are not really funny, but they are used in change log
  428.    so we emulate the best we can.  */
  429. gethostname (p, size)
  430.      char *p;
  431.      int size;
  432. {
  433.   char *q = egetenv ("HOSTNAME");
  434.  
  435.   if (!q) q = "pc";
  436.   strcpy (p, q);
  437.   return 0;
  438. }
  439.  
  440. /* Destructively turn backslashes into slashes.  */
  441. void
  442. dostounix_filename (p)
  443.      register char *p;
  444. {
  445.   while (*p)
  446.     {
  447.       if (*p == '\\')
  448.     *p = '/';
  449.       p++;
  450.     }
  451. }
  452.  
  453. /* Destructively turn slashes into backslashes.  */
  454. void
  455. unixtodos_filename (p)
  456.      register char *p;
  457. {
  458.   while (*p)
  459.     {
  460.       if (*p == '/')
  461.     *p = '\\';
  462.       p++;
  463.     }
  464. }
  465.  
  466. /* Get the default directory for a given drive.  0=def, 1=A, 2=B, ...  */
  467. int
  468. getdefdir (drive, dst)
  469.      int drive;
  470.      char *dst;
  471. {
  472.   union REGS regs;
  473.  
  474.   *dst++ = '/';
  475.   regs.h.dl = drive;
  476.   regs.x.si = (int) dst;
  477.   regs.h.ah = 0x47;
  478.   intdos (®s, ®s);
  479.   return !regs.x.cflag;
  480. }
  481.  
  482. /* Remove all CR's that are followed by a LF.  */
  483. int
  484. crlf_to_lf (n, buf)
  485.      register int n;
  486.      register unsigned char *buf;
  487. {
  488.   unsigned char *np = buf;
  489.   unsigned char *startp = buf;
  490.   unsigned char *endp = buf + n;
  491.   unsigned char c;
  492.  
  493.   if (n == 0)
  494.     return n;
  495.   while (buf < endp - 1)
  496.     {
  497.       if (*buf == 0x0d)
  498.     {
  499.       if (*(++buf) != 0x0a)
  500.         *np++ = 0x0d;
  501.     }
  502.       else
  503.     *np++ = *buf++;
  504.     }
  505.   if (buf < endp)
  506.     *np++ = *buf++;
  507.   return np - startp;
  508. }
  509.  
  510.  
  511. /* Run command as specified by ARGV in directory DIR.
  512.    The command is run with input from TEMPIN and output to file TEMPOUT.  */
  513. int
  514. run_msdos_command (argv, dir, tempin, tempout)
  515.      unsigned char **argv;
  516.      Lisp_Object dir;
  517.      int tempin, tempout;
  518. {
  519.   char *saveargv1, *saveargv2, **envv;
  520.   char oldwd[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
  521.   int msshell, result = -1;
  522.   int in, out, inbak, outbak, errbak;
  523.   Lisp_Object cmd;
  524.  
  525.   /* Get current directory as MSDOS cwd is not per-process.  */
  526.   getwd (oldwd);
  527.  
  528.   cmd = Ffile_name_nondirectory (build_string (argv[0]));
  529.   msshell = !NILP (Fmember (cmd, Fsymbol_value (intern ("msdos-shells"))))
  530.     && !strcmp ("-c", argv[1]);
  531.   if (msshell)
  532.     {
  533.       saveargv1 = argv[1];
  534.       saveargv2 = argv[2];
  535.       argv[1] = "/c";
  536.       if (argv[2])
  537.     {
  538.       char *p = alloca (strlen (argv[2]) + 1);
  539.  
  540.       strcpy (argv[2] = p, saveargv2);
  541.       while (*p && isspace (*p))
  542.         p++;
  543.       while (*p && !isspace (*p))
  544.         if (*p == '/')
  545.           *p++ = '\\';
  546.         else
  547.           p++;
  548.     }
  549.     }
  550.  
  551.   /* Build the environment array.  */
  552.   {
  553.     extern Lisp_Object Vprocess_environment;
  554.     Lisp_Object tmp, lst;
  555.     int i, len;
  556.  
  557.     lst = Vprocess_environment;
  558.     len = XFASTINT (Flength (lst));
  559.  
  560.     envv = alloca ((len + 1) * sizeof (char *));
  561.     for (i = 0; i < len; i++)
  562.       {
  563.     tmp = Fcar (lst);
  564.     lst = Fcdr (lst);
  565.     CHECK_STRING (tmp, 0);
  566.     envv[i] = alloca (XSTRING (tmp)->size + 1);
  567.     strcpy (envv[i], XSTRING (tmp)->data);
  568.       }
  569.     envv[len] = (char *) 0;
  570.   }
  571.  
  572.   if (XTYPE (dir) == Lisp_String)
  573.     chdir (XSTRING (dir)->data);
  574.   inbak = dup (0);
  575.   outbak = dup (1);
  576.   errbak = dup (2);
  577.   if (inbak < 0 || outbak < 0 || errbak < 0)
  578.     goto done; /* Allocation might fail due to lack of descriptors.  */
  579.   dup2 (tempin, 0);
  580.   dup2 (tempout, 1);
  581.   dup2 (tempout, 2);
  582.   dos_ttcooked ();
  583.   result = spawnve (P_WAIT, argv[0], argv, envv);
  584.   dos_ttraw ();
  585.   dup2 (inbak, 0);
  586.   dup2 (outbak, 1);
  587.   dup2 (errbak, 2);
  588.  
  589.  done:
  590.   chdir (oldwd);
  591.   if (msshell)
  592.     {
  593.       argv[1] = saveargv1;
  594.       argv[2] = saveargv2;
  595.     }
  596.   return result;
  597. }
  598.  
  599.  
  600. croak (badfunc)
  601.      char *badfunc;
  602. {
  603.   fprintf (stderr, "%s not yet implemented\r\n", badfunc);
  604.   reset_sys_modes ();
  605.   exit (1);
  606. }
  607.  
  608. /* A list of unimplemented functions that we silently ignore.  */
  609. unsigned alarm (s) unsigned s; {}
  610. fork () { return 0; }
  611. int kill (x, y) int x, y; { return -1; }
  612. nice (p) int p; {}
  613. void volatile pause () {}
  614. request_sigio () {}
  615. setpgrp () {return 0; }
  616. setpriority (x,y,z) int x,y,z; { return 0; }
  617. sigsetmask (x) int x; { return 0; }
  618. unrequest_sigio () {}
  619.  
  620. #ifdef chdir
  621. #undef chdir
  622. #endif
  623.  
  624. int
  625. sys_chdir (path)
  626.      const char* path;
  627. {
  628.   int len = strlen (path);
  629.   char *tmp = (char *) alloca (len + 1);
  630.   /* Gotta do this extern here due to the corresponding #define: */
  631.   extern int chdir ();
  632.  
  633.   if (*path && path[1] == ':' && (getdisk () != tolower (path[0]) - 'a'))
  634.     setdisk (tolower (path[0]) - 'a');
  635.  
  636.   strcpy (tmp, path);
  637.   if (strcmp (path, "/") && strcmp (path + 1, ":/") && (path[len - 1] == '/'))
  638.     tmp[len - 1] = 0;
  639.   return chdir (tmp);
  640. }
  641.  
  642. /* Sleep SECS.  If KBDOK also return immediately if a key is pressed.  */
  643. void
  644. sleep_or_kbd_hit (secs, kbdok)
  645.      int secs, kbdok;
  646. {
  647.   long clnow, clthen;
  648.   struct timeval t;
  649.  
  650.   gettimeofday (&t, NULL);
  651.   clnow = t.tv_sec * 100 + t.tv_usec / 10000;
  652.   clthen = clnow + (100 * secs);
  653.  
  654.   do
  655.     {
  656.       gettimeofday (&t, NULL);
  657.       clnow = t.tv_sec * 100 + t.tv_usec / 10000;
  658.       if (kbdok && detect_input_pending ())
  659.     return;
  660.     }
  661.   while (clnow < clthen);
  662. }
  663.  
  664. /* The Emacs root directory as determined by init_environment.  */
  665. static char emacsroot[MAXPATHLEN];
  666.  
  667. char *
  668. rootrelativepath (rel)
  669.      char *rel;
  670. {
  671.   static char result[MAXPATHLEN + 10];
  672.  
  673.   strcpy (result, emacsroot);
  674.   strcat (result, "/");
  675.   strcat (result, rel);
  676.   return result;
  677. }
  678.  
  679. /* Define a lot of environment variables if not already defined.  Don't
  680.    remove anything unless you know what you're doing -- lots of code will
  681.    break if one or more of these are missing.  */
  682. void
  683. init_environment (argc, argv, skip_args)
  684.      int argc;
  685.      char **argv;
  686.      int skip_args;
  687. {
  688.   char *s, *t, *root;
  689.   int len;
  690.  
  691.   /* Find our root from argv[0].  Assuming argv[0] is, say,
  692.      "c:/emacs/bin/emacs.exe" our root will be "c:/emacs".  */
  693.   len = strlen (argv[0]);
  694.   root = alloca (len + 10);  /* A little extra space for the stuff below.  */
  695.   strcpy (root, argv[0]);
  696.   while (len > 0 && root[len] != '/' && root[len] != ':')
  697.     len--;
  698.   root[len] = '\0';
  699.   if (len > 4 && strcmp (root + len - 4, "/bin") == 0)
  700.     root[len - 4] = '\0';
  701.   else
  702.     strcpy (root, "c:/emacs");  /* Only under debuggers, I think.  */
  703.   len = strlen (root);
  704.   strcpy (emacsroot, root);
  705.  
  706.   /* We default HOME to our root.  */
  707.   setenv ("HOME", root, 0);
  708.  
  709.   /* We default EMACSPATH to root + "/bin".  */
  710.   strcpy (root + len, "/bin");
  711.   setenv ("EMACSPATH", root, 0);
  712.  
  713.   /* I don't expect anybody to ever use other terminals so the internal
  714.      terminal is the default.  */
  715.   setenv ("TERM", "internal", 0);
  716.  
  717.   /* SHELL is a bit tricky -- COMSPEC is the closest we come, but we must
  718.      downcase it and mirror the backslashes.  */
  719.   s = getenv ("COMSPEC");
  720.   if (!s) s = "c:/command.com";
  721.   t = alloca (strlen (s) + 1);
  722.   strcpy (t, s);
  723.   strlwr (t);
  724.   dostounix_filename (t);
  725.   setenv ("SHELL", t, 0);
  726.  
  727.   /* PATH is also downcased and backslashes mirrored.  */
  728.   s = getenv ("PATH");
  729.   if (!s) s = "";
  730.   t = alloca (strlen (s) + 3);
  731.   /* Current directory is always considered part of MsDos's path but it is
  732.      not normally mentioned.  Now it is.  */
  733.   strcat (strcpy (t, ".;"), s);
  734.   strlwr (t);
  735.   dostounix_filename (t); /* Not a single file name, but this should work.  */
  736.   setenv ("PATH", t, 1);
  737.  
  738.   /* In some sense all dos users have root privileges, so...  */
  739.   setenv ("USER", "root", 0);
  740.   setenv ("NAME", getenv ("USER"), 0);
  741.  
  742.   /* Time zone determined from country code.  To make this possible, the
  743.      country code may not span more than one time zone.  In other words,
  744.      in the USA, you lose.  */
  745.   switch (dos_country_code)
  746.     {
  747.     case 31: /* Belgium */
  748.     case 32: /* The Netherlands */
  749.     case 33: /* France */
  750.     case 34: /* Spain */
  751.     case 36: /* Hungary */
  752.     case 38: /* Yugoslavia (or what's left of it?) */
  753.     case 39: /* Italy */
  754.     case 41: /* Switzerland */
  755.     case 42: /* Tjekia */
  756.     case 45: /* Denmark */
  757.     case 46: /* Sweden */
  758.     case 47: /* Norway */
  759.     case 48: /* Poland */
  760.     case 49: /* Germany */
  761.       /* Daylight saving from last Sunday in March to last Sunday in
  762.      September, both at 2AM.  */
  763.       setenv ("TZ", "MET-01METDST-02,M3.5.0/02:00,M9.5.0/02:00", 0);
  764.       break;
  765.     case 44: /* United Kingdom */
  766.     case 351: /* Portugal */
  767.     case 354: /* Iceland */
  768.       setenv ("TZ", "GMT+00", 0);
  769.       break;
  770.     case 81: /* Japan */
  771.     case 82: /* Korea */
  772.       setenv ("TZ", "???-09", 0);
  773.       break;
  774.     case 90: /* Turkey */
  775.     case 358: /* Finland */
  776.     case 972: /* Israel */
  777.       setenv ("TZ", "EET-02", 0);
  778.       break;
  779.     }
  780.   tzset ();
  781.   init_gettimeofday ();
  782. }
  783.  
  784. /* Flash the screen as a substitute for BEEPs.  */
  785.  
  786. static void
  787. do_visible_bell (xorattr)
  788.      unsigned char xorattr;
  789. {
  790.   asm volatile
  791.     ("  movb   $1,%%dl
  792. visible_bell_0:
  793.     movl   _ScreenPrimary,%%eax
  794.     call   dosmemsetup
  795.     movl   %%eax,%%ebx
  796.     movl   %1,%%ecx
  797.     movb   %0,%%al
  798.     incl   %%ebx
  799. visible_bell_1:
  800.     xorb   %%al,%%gs:(%%ebx)
  801.     addl   $2,%%ebx
  802.     decl   %%ecx
  803.     jne    visible_bell_1
  804.     decb   %%dl
  805.     jne    visible_bell_3
  806. visible_bell_2:
  807.     movzwl %%ax,%%eax
  808.         movzwl %%ax,%%eax
  809.     movzwl %%ax,%%eax
  810.     movzwl %%ax,%%eax
  811.     decw   %%cx
  812.     jne    visible_bell_2
  813.     jmp    visible_bell_0
  814. visible_bell_3:"
  815.      : /* no output */
  816.      : "m" (xorattr), "g" (ScreenCols () * ScreenRows ())
  817.      : "%eax", "%ebx", /* "%gs",*/ "%ecx", "%edx");
  818. }
  819.  
  820. /* At screen position (X,Y), output C characters from string S with
  821.    attribute A.  Do it fast!  */
  822.  
  823. static void
  824. output_string (x, y, s, c, a)
  825.      int x, y, c;
  826.      unsigned char *s;
  827.      unsigned char a;
  828. {
  829.   char *t = (char *)ScreenPrimary + 2 * (x + ScreenCols () * y);
  830.   asm volatile
  831.     ("  movl   %1,%%eax
  832.         call   dosmemsetup
  833.         movl   %%eax,%%edi
  834.         movb   %0,%%ah
  835.         movl   %2,%%ecx
  836.         movl   %3,%%esi
  837. output_string1:
  838.         movb   (%%esi),%%al
  839.         movw   %%ax,%%gs:(%%edi)
  840.         addl   $2,%%edi
  841.         incl   %%esi
  842.         decl   %%ecx
  843.         jne    output_string1"
  844.      : /* no output */
  845.      : "m" (a), "g" (t), "g" (c), "g" (s)
  846.      : "%eax", "%ecx", /* "%gs",*/ "%esi", "%edi");
  847. }
  848.  
  849. static int internal_terminal = 0;
  850. #undef fflush
  851.  
  852. int
  853. internal_flush (f)
  854.      FILE *f;
  855. {
  856.   static char spaces[] = "                                                                                ";
  857.   static int x;
  858.   static int y;
  859.   unsigned char *cp, *cp0;
  860.   int count, i, j;
  861.  
  862.   if (internal_terminal && f == stdout)
  863.     {
  864.       if (have_mouse) mouse_off ();
  865.       cp = stdout->_base;
  866.       count = stdout->_ptr - stdout->_base;
  867.       while (count > 0)
  868.     {
  869.       switch (*cp++)
  870.         {
  871.         case 27:
  872.           switch (*cp++)
  873.         {
  874.         case '@':
  875.           y = *cp++;
  876.           x = *cp++;
  877.           count -= 4;
  878.           break;
  879.         case 'A':
  880.           ScreenAttrib = *cp++;
  881.           count -= 3;
  882.           break;
  883.         case 'B':
  884.           do_visible_bell (*cp++);
  885.           count -= 3;
  886.           break;
  887.         case 'C':
  888.           ScreenClear ();
  889.           x = y = 0;
  890.           count -= 2;
  891.           break;
  892.         case 'E':
  893.           i = ScreenCols () - x;
  894.           j = x;
  895.           while (i >= sizeof spaces)
  896.             {
  897.               output_string (j, y, spaces, sizeof spaces,
  898.                      ScreenAttrib);
  899.               j += sizeof spaces;
  900.               i -= sizeof spaces;
  901.             }
  902.           if (i > 0)
  903.             output_string (j, y, spaces, i, ScreenAttrib);
  904.           count -= 2;
  905.           break;
  906.         case 'R':
  907.           x++;
  908.           count -= 2;
  909.           break;
  910.         case 'U':
  911.           y--;
  912.           count -= 2;
  913.           break;
  914.         case 'X':
  915.           ScreenAttrib ^= *cp++;
  916.           count -= 3;
  917.           break;
  918.         default:
  919.           count -= 2;
  920.         }
  921.           break;
  922.         case 7:
  923.           write (1, "\007", 1);
  924.           count--;
  925.           break;
  926.         case 8:
  927.           x--;
  928.           count--;
  929.           break;
  930.         case 13:
  931.           x = 0;
  932.           count--;
  933.           break;
  934.         case 10:
  935.           y++;
  936.           count--;
  937.           break;
  938.         default:
  939.           cp0 = cp - 1;
  940.           count--;
  941.           while (count > 0 && *cp >= ' ')
  942.         cp++, count--;
  943.           output_string (x, y, cp0, cp - cp0, ScreenAttrib);
  944.           x += (cp - cp0);
  945.         }
  946.     }
  947.       fpurge (stdout);
  948.       ScreenSetCursor (y, x);
  949.       if (have_mouse) mouse_on ();
  950.     }
  951.   else
  952.     /* This is a call to the original fflush.  */
  953.     fflush (f);
  954. }
  955.  
  956. /* Do we need the internal terminal? */
  957. void
  958. internal_terminal_init ()
  959. {
  960.   char *term = getenv ("TERM");
  961.  
  962.   internal_terminal
  963.     = (!noninteractive) && term && !strcmp (term, "internal");
  964. }
  965.  
  966. /* When time zones are set from Ms-Dos too may C-libraries are playing
  967.    tricks with time values.  We solve this by defining our own version
  968.    of `gettimeofday' bypassing GO32.  Our version needs to be initialized
  969.    once and after each call to `tzset' with TZ changed.  */
  970.  
  971. static int daylight, gmtoffset;
  972.  
  973. int
  974. gettimeofday (struct timeval *tp, struct timezone *tzp)
  975. {
  976.   if (tp)
  977.     {
  978.       struct time t;
  979.       struct date d;
  980.       struct tm tmrec;
  981.  
  982.       gettime (&t);
  983.       getdate (&d);
  984.       tmrec.tm_year = d.da_year - 1900;
  985.       tmrec.tm_mon = d.da_mon - 1;
  986.       tmrec.tm_mday = d.da_day;
  987.       tmrec.tm_hour = t.ti_hour;
  988.       tmrec.tm_min = t.ti_min;
  989.       tmrec.tm_sec = t.ti_sec;
  990.       tmrec.tm_gmtoff = gmtoffset;
  991.       tmrec.tm_isdst = daylight;
  992.       tp->tv_sec = mktime (&tmrec);
  993.       tp->tv_usec = t.ti_hund * (1000000 / 100);
  994.     }
  995.   if (tzp)
  996.     {
  997.       tzp->tz_minuteswest = gmtoffset;
  998.       tzp->tz_dsttime = daylight;
  999.     }
  1000.   return 0;
  1001. }
  1002.  
  1003. void
  1004. init_gettimeofday ()
  1005. {
  1006.   time_t ltm, gtm;
  1007.   struct tm *lstm;
  1008.  
  1009.   daylight = 0;
  1010.   gmtoffset = 0;
  1011.   ltm = gtm = time (NULL);
  1012.   ltm = mktime (lstm = localtime (<m));
  1013.   gtm = mktime (gmtime (>m));
  1014.   daylight = lstm->tm_isdst;
  1015.   gmtoffset = (int)(gtm - ltm) / 60;
  1016. }
  1017.  
  1018. /* These must be global.  */
  1019. static _go32_dpmi_seginfo ctrl_break_vector;
  1020. static _go32_dpmi_registers ctrl_break_regs;
  1021. static int ctrlbreakinstalled = 0;
  1022.  
  1023. /* Interrupt level detection of Ctrl-Break.  Don't do anything fancy here!  */
  1024. void
  1025. ctrl_break_func (regs)
  1026.      _go32_dpmi_registers *regs;
  1027. {
  1028.   Vquit_flag = Qt;
  1029. }
  1030.  
  1031. void
  1032. install_ctrl_break_check ()
  1033. {
  1034.   if (!ctrlbreakinstalled)
  1035.     {
  1036.       /* Don't press Ctrl-Break if you don't have either DPMI or Emacs
  1037.      was compiler with Djgpp 1.11 maintenance level 5 or later!  */
  1038.       ctrlbreakinstalled = 1;
  1039.       ctrl_break_vector.pm_offset = (int) ctrl_break_func;
  1040.       _go32_dpmi_allocate_real_mode_callback_iret (&ctrl_break_vector,
  1041.                            &ctrl_break_regs);
  1042.       _go32_dpmi_set_real_mode_interrupt_vector (0x1b, &ctrl_break_vector);
  1043.     }
  1044. }
  1045.  
  1046.  
  1047. /* Mouse routines under devellopment follow.  Coordinates are in screen
  1048.    positions and zero based.  Mouse buttons are numbered from left to 
  1049.    right and also zero based.  */
  1050.  
  1051. static int mouse_button_translate[NUM_MOUSE_BUTTONS];
  1052. static int mouse_button_count;
  1053.  
  1054. void
  1055. mouse_init ()
  1056. {
  1057.   union REGS regs;
  1058.  
  1059.   regs.x.ax = 0x0007;
  1060.   regs.x.cx = 0;
  1061.   regs.x.dx = 8 * (ScreenCols () - 1);
  1062.   int86 (0x33, ®s, ®s);
  1063.  
  1064.   regs.x.ax = 0x0008;
  1065.   regs.x.cx = 0;
  1066.   regs.x.dx = 8 * (ScreenRows () - 1);
  1067.   int86 (0x33, ®s, ®s);
  1068.  
  1069.   mouse_moveto (ScreenCols () - 1, ScreenRows () - 1);
  1070.   mouse_on ();
  1071. }
  1072.  
  1073. void
  1074. mouse_on ()
  1075. {
  1076.   union REGS regs;
  1077.  
  1078.   regs.x.ax = 0x0001;
  1079.   int86 (0x33, ®s, ®s);
  1080. }
  1081.  
  1082. void
  1083. mouse_off ()
  1084. {
  1085.   union REGS regs;
  1086.  
  1087.   regs.x.ax = 0x0002;
  1088.   int86 (0x33, ®s, ®s);
  1089. }
  1090.  
  1091. void
  1092. mouse_moveto (x, y)
  1093.      int x, y;
  1094. {
  1095.   union REGS regs;
  1096.  
  1097.   regs.x.ax = 0x0004;
  1098.   mouse_last_x = regs.x.cx = x * 8;
  1099.   mouse_last_y = regs.x.dx = y * 8;
  1100.   int86 (0x33, ®s, ®s);
  1101. }
  1102.  
  1103. int
  1104. mouse_pressed (b, xp, yp)
  1105.      int b, *xp, *yp;
  1106. {
  1107.   union REGS regs;
  1108.  
  1109.   if (b >= mouse_button_count)
  1110.     return 0;
  1111.   regs.x.ax = 0x0005;
  1112.   regs.x.bx = mouse_button_translate[b];
  1113.   int86 (0x33, ®s, ®s);
  1114.   if (regs.x.bx)
  1115.     *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
  1116.   return (regs.x.bx != 0);
  1117. }
  1118.  
  1119. int
  1120. mouse_released (b, xp, yp)
  1121.      int b, *xp, *yp;
  1122. {
  1123.   union REGS regs;
  1124.  
  1125.   if (b >= mouse_button_count)
  1126.     return 0;
  1127.   regs.x.ax = 0x0006;
  1128.   regs.x.bx = mouse_button_translate[b];
  1129.   int86 (0x33, ®s, ®s);
  1130.   if (regs.x.bx)
  1131.     *xp = regs.x.cx / 8, *yp = regs.x.dx / 8;
  1132.   return (regs.x.bx != 0);
  1133. }
  1134.  
  1135. void
  1136. mouse_get_pos (f, bar_window, part, x, y, time)
  1137.      FRAME_PTR *f;
  1138.      Lisp_Object *bar_window, *x, *y;
  1139.      enum scroll_bar_part *part;
  1140.      unsigned long *time;
  1141. {
  1142.   union REGS regs;
  1143.   struct timeval tv;
  1144.  
  1145.   regs.x.ax = 0x0003;
  1146.   int86 (0x33, ®s, ®s);
  1147.   *f = selected_frame;
  1148.   *bar_window = Qnil;
  1149.   gettimeofday (&tv, NULL);
  1150.   *x = make_number (regs.x.cx / 8);
  1151.   *y = make_number (regs.x.dx / 8);
  1152.   *time = tv.tv_usec;
  1153.   mouse_moved = 0;
  1154. }
  1155.  
  1156. void
  1157. mouse_check_moved ()
  1158. {
  1159.   union REGS regs;
  1160.  
  1161.   regs.x.ax = 0x0003;
  1162.   int86 (0x33, ®s, ®s);
  1163.   if (regs.x.cx != mouse_last_x || regs.x.dx != mouse_last_y)
  1164.     {
  1165.       mouse_moved = 1;
  1166.       mouse_last_x = regs.x.cx;
  1167.       mouse_last_y = regs.x.dx;
  1168.     }
  1169. }
  1170.  
  1171. int
  1172. mouse_init1 ()
  1173. {
  1174.   union REGS regs;
  1175.   int present;
  1176.  
  1177.   if (!internal_terminal)
  1178.     return 0;
  1179.  
  1180.   regs.x.ax = 0x0021;
  1181.   int86 (0x33, ®s, ®s);
  1182.   present = (regs.x.ax & 0xffff) == 0xffff;
  1183.   if (!present)
  1184.     {
  1185.       /* Reportedly, the above doesn't work for some mouse drivers.  There
  1186.      is an additional detection method that should work, but might be
  1187.      a little slower.  Use that as an alternative.  */
  1188.       regs.x.ax = 0x0000;
  1189.       int86 (0x33, ®s, ®s);
  1190.       present = (regs.x.ax & 0xffff) == 0xffff;
  1191.     }
  1192.  
  1193.   if (present)
  1194.     {
  1195.       if (regs.x.bx == 3)
  1196.     {
  1197.       mouse_button_count = 3;
  1198.       mouse_button_translate[0] = 0; /* Left */
  1199.       mouse_button_translate[1] = 2; /* Middle */
  1200.       mouse_button_translate[2] = 1; /* Right */
  1201.     }
  1202.       else
  1203.     {
  1204.       mouse_button_count = 2;
  1205.       mouse_button_translate[0] = 0;
  1206.       mouse_button_translate[1] = 1;
  1207.     }
  1208.       mouse_position_hook = &mouse_get_pos;
  1209.       mouse_init ();
  1210.    }
  1211.   return present;
  1212. }
  1213.  
  1214. /* See xterm.c for more info.  */
  1215. void
  1216. pixel_to_glyph_coords (f, pix_x, pix_y, x, y, bounds, noclip)
  1217.      FRAME_PTR f;
  1218.      register int pix_x, pix_y;
  1219.      register int *x, *y;
  1220.      void /* XRectangle */ *bounds;
  1221.      int noclip;
  1222. {
  1223.   if (bounds) abort ();
  1224.  
  1225.   /* Ignore clipping.  */
  1226.  
  1227.   *x = pix_x;
  1228.   *y = pix_y;
  1229. }
  1230.  
  1231. void
  1232. glyph_to_pixel_coords (f, x, y, pix_x, pix_y)
  1233.      FRAME_PTR f;
  1234.      register int x, y;
  1235.      register int *pix_x, *pix_y;
  1236. {
  1237.   *pix_x = x;
  1238.   *pix_y = y;
  1239. }
  1240.  
  1241. #endif /* MSDOS */
  1242.